<?php

// +----------------------------------------------------------------------
// | Copyright (c) 2015－03－21 http://www.cencn.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: 林群伟  <56583965@qq.com> <http://www.xzqly.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | 微信SDK
// +----------------------------------------------------------------------
require_once "WxConfig.php";
require_once "WxException.php";

class WXSDK {

    /**
     * 创建菜单
     */
    public function createMenu($inputObj, $access_token, $data) {
        if (!$inputObj->IsAppidSet()) {
            throw new WxPayException("微信Appid不能放空！");
        } else if (!$inputObj->IsAppSecretSet()) {
            throw new WxPayException("微信AppSecret不能放空！");
        }
        $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" . $access_token;
        $r = $this->postXmlCurl($data, $url);
        $arr = json_decode($r, true);

        if (empty($arr['errcode'])) {
            return 'ok';
        } else {
            throw new \WxPayException("返回结果错误:" . $arr["errmsg"]);
        }
    }

    /**
     * 获取AccessToken
     */
    public function get_AccessToken($inputObj) {
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $inputObj->GetAppid() . '&secret=' . $inputObj->GetAppSecret();
        $data = array();
        $r = $this->postXmlCurl($data, $url);
        $arr = json_decode($r, true);
        if (empty($arr["access_token"])) {
            throw new \WxPayException("返回结果错误:" . $arr["errmsg"]);
        }
        return $arr['access_token'];
    }

    /**
     * 获取微信公众号用户openid
     */
    public function getUserOpenIdList($access_token, $next_openid) {
        $url = 'https://api.weixin.qq.com/cgi-bin/user/get?access_token=' . $access_token . '&next_openid=' . $next_openid;
        $data = $this->getCurl($url);
        $arr = json_decode($data, true);
        if ($arr["errcode"]) {
            throw new \WxPayException("返回结果错误:" . $arr["errmsg"]);
        }
        return $arr;
    }

    /**
     * 根据openid获取关注公众号用户信息
     */
    public function getOpenIdSetUserInfo($access_token, $openid) {
        $url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $access_token . '&openid=' . $openid . '&lang=zh_CN';
        $data = $this->getCurl($url);
        $arr = json_decode($data, true);
        if ($arr["errcode"]) {
            throw new \WxPayException("返回结果错误:" . $arr["errmsg"]);
        }
        return $arr;
    }

    /**
     * 批量获取用户基本信息
     */
    public function getOpenIdSetUserListInfo($access_token, $data) {
        $url = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=" . $access_token;
        $r = $this->postXmlCurl($data, $url);

        $arr = json_decode($r, true);
        if (!empty($arr["errcode"])) {
            throw new \WxPayException("返回结果错误:" . $arr["errmsg"]);
        }
        return $arr;
    }

    
    
    /**
     * 授权用户登陆
     */
    public function getAuthorizedUserLoginInfo($inputObj) {
        if (!$inputObj->IsAppidSet()) {
            throw new WxPayException("微信Appid不能放空！");
        } else if (!$inputObj->IsAppSecretSet()) {
            throw new WxPayException("微信AppSecret不能放空！");
        }
         $code = isset($_GET['code']) ? trim($_GET['code']) : '';
         if (empty($code)) {
                $redirect_uri = $inputObj->GetCurUrl();
                $state = "";
                $sAppId = $inputObj->GetAppid();
                $scope = 'snsapi_userinfo';
                $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $sAppId . '&redirect_uri=' . rawurlencode($redirect_uri) . '&response_type=code&scope=' . $scope . '&state=' . $state . '#wechat_redirect';
                $inputObj->redirect($url);
         }else{
                 $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' .  $inputObj->GetAppid() . '&secret=' .  $inputObj->GetAppSecret() . '&code=' . $code . '&grant_type=authorization_code';
                $result = $this->getCurl($url);
                $data = json_decode($result, 1);
                 $openid = isset($data['openid']) ? trim(($data['openid'])) : '';
                if ($openid) {
                    $url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $data["access_token"] . '&openid=' . $openid;
                    $result = $this->getCurl($url);
                    $userdata = json_decode($result, 1);
                    return $userdata;
                } else {
                    return "";
                }
         }      
        
    }
    /**
     * 以post方式提交xml到对应的接口url
     * 
     * @param string $xml  需要post的xml数据或者是data 数据
     * @param string $url  url
     * @param bool $useCert 是否需要证书，默认不需要
     * @param int $second   url执行超时时间，默认30s
     * @throws WxPayException
     */
    private static function postXmlCurl($xml, $url, $useCert = false, $second = 30) {
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);

        //如果有配置代理这里就设置代理
        if (\WxConfig::CURL_PROXY_HOST != "0.0.0.0" && \WxConfig::CURL_PROXY_PORT != 0) {
            curl_setopt($ch, CURLOPT_PROXY, \WxConfig::CURL_PROXY_HOST);
            curl_setopt($ch, CURLOPT_PROXYPORT, \WxConfig::CURL_PROXY_PORT);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //严格校验
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

        if ($useCert == true) {
            //设置证书
            //使用证书：cert 与 key 分别属于两个.pem文件
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLCERT, \WxConfig::SSLCERT_PATH);
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLKEY, \WxConfig::SSLKEY_PATH);
        }
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            throw new \WxPayException("curl出错，错误码:$error");
        }
    }

    /**
     * 以GET 方式提交
     */
    public function getCurl($url, $second = 30) {
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 0);
        $data = curl_exec($ch);
        //返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            throw new \WxPayException("curl出错，错误码:$error");
        }
    }

}

/**
 * 微信基础类
 */
class WXBase {

    protected $values = array();
    protected $userList = array();

    /**
     * 设置签名，详见签名生成算法
     * @param string $value 
     * */
    public function SetSign() {
        $sign = $this->MakeSign();
        $this->values['sign'] = $sign;
        return $sign;
    }

    /**
     * 获取签名，详见签名生成算法的值
     * @return 值
     * */
    public function GetSign() {
        return $this->values['sign'];
    }

    /**
     * 判断签名，详见签名生成算法是否存在
     * @return true 或 false
     * */
    public function IsSignSet() {
        return array_key_exists('sign', $this->values);
    }

    /**
     * 输出xml字符
     * @throws WxPayException
     * */
    public function ToXml() {
        if (!is_array($this->values) || count($this->values) <= 0) {
            throw new \WxPayException("数组数据异常！");
        }

        $xml = "<xml>";
        foreach ($this->values as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 将xml转为array
     * @param string $xml
     * @throws WxPayException
     */
    public function FromXml($xml) {
        if (!$xml) {
            throw new \WxPayException("xml数据异常！");
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $this->values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $this->values;
    }

    /**
     * 格式化参数格式化成url参数
     */
    public function ToUrlParams() {
        $buff = "";
        foreach ($this->values as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 生成签名
     * @return 签名，本函数不覆盖sign成员变量，如要设置签名需要调用SetSign方法赋值
     */
    public function MakeSign() {
        //签名步骤一：按字典序排序参数
        ksort($this->values);
        $string = $this->ToUrlParams();
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . WxPayConfig::KEY;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    /**
     * 获取设置的值
     */
    public function GetValues() {
        return $this->values;
    }

    /**
     * 数组的json 表示
     */
    public function setDataMenu($tree) {
        $newdata = array();
        $i = 0;
        foreach ($tree as $tk => $tv) {    //生成微信数组
            if (empty($tv['_child'])) {      //子菜单为空时操作
                $newdata["button"][$i]['type'] = $tv["type"];
                $newdata["button"][$i]['name'] = $tv["title"];
                $newdata["button"][$i]['url'] = $tv["link_id"];
            } else {
                $newdata["button"][$i]["name"] = $tv["title"];
                foreach ($tv['_child'] as $tvk => $tvv) {   //有子菜单生成
                    $newdata["button"][$i]["sub_button"][$tvk]['type'] = $tvv["type"];
                    $newdata["button"][$i]["sub_button"][$tvk]['name'] = $tvv["title"];
                    $newdata["button"][$i]["sub_button"][$tvk]['url'] = $tvv["link_id"];
                }
                $i++;
            }
        }
        return json_encode($newdata, JSON_UNESCAPED_UNICODE);
    }

    /**
     * 名字转化
     */
    // 处理带Emoji的数据，type=0表示写入数据库前的emoji转为HTML，为1时表示HTML转为emoji码
    function deal_emoji($msg, $type = 1) {
        if ($type == 0) {
            $msg = urlencode($msg);
            $msg = json_encode($msg);
        } else {

            $msg = preg_replace("#\\\u([0-9a-f]+)#ie", "iconv('UCS-2','UTF-8', pack('H4', '\\1'))", $msg);

            // $msg = preg_replace("#(\\\ue[0-9a-f]{3})#ie", "addslashes('\\1')",$msg);

            $msg = urldecode($msg);
            // $msg = json_decode ( $msg );
            // dump($msg);
            $msg = str_replace('"', "", $msg);
            // dump($msg);exit;
            if ($txt !== null) {
                $msg = $txt;
            }
        }

        return $msg;
    }

    // php获取当前访问的完整url地址
    function GetCurUrl() {
        $url = 'http://';
        if (isset($_SERVER ['HTTPS']) && $_SERVER ['HTTPS'] == 'on') {
            $url = 'https://';
        }
        if ($_SERVER ['SERVER_PORT'] != '80') {
            $url .= $_SERVER ['HTTP_HOST'] . ':' . $_SERVER ['SERVER_PORT'] . $_SERVER ['REQUEST_URI'];
        } else {
            $url .= $_SERVER ['HTTP_HOST'] . $_SERVER ['REQUEST_URI'];
        }
        // 兼容后面的参数组装
        if (stripos($url, '?') === false) {
            $url .= '?t=' . time();
        }
        return $url;
    }

    /**
     * URL重定向
     * @param string $url 重定向的URL地址
     * @param integer $time 重定向的等待时间（秒）
     * @param string $msg 重定向前的提示信息
     * @return void
     */
    function redirect($url, $time = 0, $msg = '') {
        //多行URL地址支持
        $url = str_replace(array("\n", "\r"), '', $url);
        if (empty($msg))
            $msg = "系统将在{$time}秒之后自动跳转到{$url}！";
        if (!headers_sent()) {
            // redirect
            if (0 === $time) {
                header('Location: ' . $url);
            } else {
                header("refresh:{$time};url={$url}");
                echo($msg);
            }
            exit();
        } else {
            $str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
            if ($time != 0)
                $str .= $msg;
            exit($str);
        }
    }

}

/**
 * 公众号菜单的操作
 */
class WXMenu extends WXBase {

    /**
     * 设置微信分配的公众账号ID
     * @param string $value 
     * */
    public function SetAppid($value) {
        $this->values['appId'] = $value;
    }

    /**
     * 获取微信分配的公众账号ID的值
     * @return 值
     * */
    public function GetAppid() {
        return $this->values['appId'];
    }

    /**
     * 判断微信分配的公众账号ID是否存在
     * @return true 或 false
     * */
    public function IsAppidSet() {
        return array_key_exists('appId', $this->values);
    }

    /**
     * 设置微信分配的公众账号secret
     * @param string $value 
     */
    public function SetAppSecret($value) {
        $this->values['appSecret'] = $value;
    }

    /**
     * 获取微信分配的公众账号appseret的值
     * @return string 
     */
    public function GetAppSecret() {
        return $this->values["appSecret"];
    }

    /**
     * 判断微信分配的公众账号ID是否存在
     * @return true 或 false
     * */
    public function IsAppSecretSet() {
        return array_key_exists('appSecret', $this->values);
    }

}

/**
 * 公众号粉丝操作类
 */
class WXFXUser extends WXBase {

    /**
     * 设置微信分配的公众账号ID
     * @param string $value 
     * */
    public function SetAppid($value) {
        $this->values['appId'] = $value;
    }

    /**
     * 获取微信分配的公众账号ID的值
     * @return 值
     * */
    public function GetAppid() {
        return $this->values['appId'];
    }

    /**
     * 判断微信分配的公众账号ID是否存在
     * @return true 或 false
     * */
    public function IsAppidSet() {
        return array_key_exists('appId', $this->values);
    }

    /**
     * 设置微信分配的公众账号secret
     * @param string $value 
     */
    public function SetAppSecret($value) {
        $this->values['appSecret'] = $value;
    }

    /**
     * 获取微信分配的公众账号appseret的值
     * @return string 
     */
    public function GetAppSecret() {
        return $this->values["appSecret"];
    }

    /**
     * 判断微信分配的公众账号ID是否存在
     * @return true 或 false
     * */
    public function IsAppSecretSet() {
        return array_key_exists('appSecret', $this->values);
    }

    /**
     * 插入数据
     */
    public function SetResultData($data) {
        $this->userList = array_merge($this->userList, $data);
    }

    public function GetResultData() {
        return $this->userList;
    }

    /**
     * 数组的json 表示
     */
    public function setDataOpenIdJson($data) {
        $newdata = array();
        $newdata["user_list"] = $data;
        return json_encode($newdata);
    }

    /**
     * 用户授权获取用户信息
     */
    public function getLoginUserInfo() {
        
    }

}

/**
 * 公众号消息操作类
 */
class WXMessage extends WXBase {
    
}

/**
 * 公众号素材类
 */
class WXShucai extends WXBase {
    
}

?>
